package com.example.mongodb;

import java.util.Arrays;
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.document.mongodb.CollectionCallback;
import org.springframework.data.document.mongodb.MongoOperations;
import org.springframework.data.document.mongodb.convert.MongoConverter;
import org.springframework.data.document.mongodb.query.*;
import org.springframework.data.document.mongodb.query.Index.Duplicates;

import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;


@Service
public class MongoService {
    @Autowired
    private MongoOperations template;

    @Autowired
    private MongoConverter converter;

    public void createCollection(final String name) {
        template.createCollection(name);
    }

    public void dropCollection(final String name) {
        template.dropCollection(name);
    }

    public void insert(final Object object, final String collection) {
        template.insert(object, collection);
    }

    public void createIndex(final String name, final String collection) {
        template.ensureIndex(
                new Index()
                        .on(name, Order.DESCENDING)
                        .unique(Duplicates.DROP),
                collection
        );
    }

    // Remove / save / ... operations here

    public long countDocuments(final String collection, final Query query) {
        return template.executeCommand(
                "{ " +
                        "\"count\" : \"" + collection + "\"," +
                        "\"query\" : " + query.getQueryObject().toString() +
                        " }").getLong("n");
    }

    public long countDocuments2(final String collection, final Query query) {
        return template.execute(collection,
                new CollectionCallback<Long>() {
                    //@Override
                    public Long doInCollection(DBCollection collection) throws MongoException, DataAccessException {
                        return collection.count(query.getQueryObject());
                    }
                }
        );
    }

    public void insert(final Collection<SimpleDocument> documents) {
        template.insert(documents, SimpleDocument.class);
    }

    public void insertOrUpdate(final SimpleDocument document) {
        final BasicDBObject dbDoc = new BasicDBObject();
        converter.write(document, dbDoc);

        template.execute(SimpleDocument.class,
                new CollectionCallback<Object>() {
                    public Object doInCollection(DBCollection collection)
                            throws MongoException, DataAccessException {
                        collection.update(new Query().addCriteria(new Criteria("name").is(document.getName()))
                                .getQueryObject(), dbDoc, true, false);

                        return null;
                    }
                }
        );
    }

    public SimpleDocument findAndModify(final Query query, final Update update) {
        return template.execute(SimpleDocument.class,
                new CollectionCallback<SimpleDocument>() {
                    //@Override
                    public SimpleDocument doInCollection(DBCollection collection)
                            throws MongoException, DataAccessException {
                        return converter.read(SimpleDocument.class,
                                collection.findAndModify(query.getQueryObject(), null, null, false,
                                        update.getUpdateObject(), true, false));
                    }
                }
        );
    }

}
